package com.yami.shop.api.controller;


import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.yami.shop.api.utils.ApacheHttp;
import com.yami.shop.api.utils.HttpClient;
import com.yami.shop.api.utils.MyUtil;
import com.yami.shop.bean.app.dto.MallDto;
import com.yami.shop.bean.app.param.WxLoginParam;
import com.yami.shop.bean.model.Mall;
import com.yami.shop.bean.model.Mp;
import com.yami.shop.bean.model.User;
import com.yami.shop.bean.param.UserRegisterParam;
import com.yami.shop.common.exception.YamiShopBindException;
import com.yami.shop.common.util.PrincipalUtil;
import com.yami.shop.dao.UserMapper;
import com.yami.shop.security.common.bo.UserInfoInTokenBO;
import com.yami.shop.security.common.dto.AuthenticationDTO;
import com.yami.shop.security.common.enums.SysTypeEnum;
import com.yami.shop.security.common.manager.PasswordCheckManager;
import com.yami.shop.security.common.manager.PasswordManager;
import com.yami.shop.security.common.manager.TokenStore;
import com.yami.shop.security.common.vo.TokenInfoVO;
import com.yami.shop.service.MallService;
import com.yami.shop.service.MpService;
import com.yami.shop.service.UserService;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Operation;
import lombok.AllArgsConstructor;
import com.yami.shop.common.response.ServerResponseEntity;
import lombok.RequiredArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.bind.annotation.*;

import jakarta.validation.Valid;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import jakarta.servlet.http.HttpServletRequest;


/**
 * 用户信息
 *
 * @author SJL
 */
@RestController
@RequestMapping("/user")
@Tag(name = "用户注册相关接口")
@RequiredArgsConstructor
public class UserRegisterController {

    private final UserService userService;
    private final MallService mallService;
    private final MpService mpService;

    private final PasswordEncoder passwordEncoder;

    private final TokenStore tokenStore;

    private final PasswordManager passwordManager;




    private final UserMapper userMapper;


    private final PasswordCheckManager passwordCheckManager;





    private Logger logger = LoggerFactory.getLogger(getClass());
    //@Value("${weixin.appid}")
    //private String appid;
//    @Value("${weixin.secret}")
//    private String secret;



    @PostMapping("/register")
    @Operation(summary = "注册" , description = "用户注册或绑定手机号接口")
    public ServerResponseEntity<TokenInfoVO> register(@Valid @RequestBody UserRegisterParam userRegisterParam) {
        if (StrUtil.isBlank(userRegisterParam.getNickName())) {
            userRegisterParam.setNickName(userRegisterParam.getUserName());
        }
        // 正在进行申请注册
        if (userService.count(new LambdaQueryWrapper<User>().eq(User::getNickName, userRegisterParam.getNickName())) > 0) {
            // 该用户名已注册，无法重新注册
            throw new YamiShopBindException("该用户名已注册，无法重新注册");
        }
        Date now = new Date();
        User user = new User();
        user.setModifyTime(now);
        user.setUserRegtime(now);
        user.setStatus(1);
        user.setNickName(userRegisterParam.getNickName());
        user.setUserMail(userRegisterParam.getUserMail());
        String decryptPassword = passwordManager.decryptPassword(userRegisterParam.getPassWord());
        user.setLoginPassword(passwordEncoder.encode(decryptPassword));
        String userId = IdUtil.simpleUUID();
        user.setUserId(userId);
        userService.save(user);
        // 2. 登录
        UserInfoInTokenBO userInfoInTokenBO = new UserInfoInTokenBO();
        userInfoInTokenBO.setUserId(user.getUserId());
        userInfoInTokenBO.setSysType(SysTypeEnum.ORDINARY.value());
        userInfoInTokenBO.setIsAdmin(0);
        userInfoInTokenBO.setEnabled(true);
        return ServerResponseEntity.success(tokenStore.storeAndGetVo(userInfoInTokenBO));
    }
    public void myLogout(HttpServletRequest request){
        String accessToken = request.getHeader("Authorization");
        if (!StrUtil.isBlank(accessToken)) {
            // 删除该用户在该系统当前的token
            tokenStore.deleteCurrentToken(accessToken);
        }

    }
    @PostMapping("/wxlogin2023/{code}")
    @Operation(summary = "微信公众号登录" , description = "微信公众号登录接口")
    public ServerResponseEntity<TokenInfoVO> wxlogin2023(HttpServletRequest request, HttpSession session, HttpServletResponse response,  @PathVariable String code,
                                                     @Valid @RequestBody WxLoginParam wxLoginParam) {
        Long mallId= Long.valueOf(wxLoginParam.getMallid());
        MallDto mall= mallService.getMallById(mallId);
        if(mall==null){
            logger.info("maill id 不存在: "+wxLoginParam.getMallid());
            myLogout(request);
            throw new YamiShopBindException("请在公众号中点击菜单进入商城");
        }
        if(code==null || "".equals(code)){
            myLogout(request);
            throw new YamiShopBindException("请在公众号"+mall.getMpName() + "中点击菜单“"+mall.getMenuName()+"”进入商城");
        }
        QueryWrapper<Mp> wrapper = new QueryWrapper<>();
        wrapper.eq("appid" , mall.getAppid());
        Mp mp =  mpService.getOne(wrapper);
        if(mp==null){
            logger.info("找不到公众号相关参数：mallid="+wxLoginParam.getMallid()+", appid="+mall.getAppid()  );
            myLogout(request);
            throw new YamiShopBindException("公众号参数没有配置，请联系系统管理员");
        }

        logger.info("==================================code="+code);
        String url="https://api.weixin.qq.com/sns/oauth2/access_token?appid="+mall.getAppid()+"&secret="+mp.getSecret()+"&code="+code+"&grant_type=authorization_code";
        logger.info("===================================url= "+url);
        String ret= HttpClient.get(url);



        logger.info("=================================get weixin  openid: "+ret);
        JSONObject json= JSON.parseObject(ret);
        String openid=null;
        String userid=null;
        String nickname=null;
        String headimgurl=null;
        Integer mallid=wxLoginParam.getMallid();
        String phone="";
        if(json.containsKey("openid")){
            openid=json.getString("openid");
            //request.setAttribute("openid", openid);
            session.setAttribute("openid",openid);
            Cookie myopenid=new Cookie("myopenid",openid);
            myopenid.setMaxAge(31536000);
            response.addCookie(myopenid);


            //access_token
            String access_token=json.getString("access_token");

            //access_token= MyUtil.getToken();
            url="https://api.weixin.qq.com/sns/userinfo?access_token="+access_token+"&openid="+openid+"&lang=zh_CN.UTF8";
            ret= ApacheHttp.get(url);
            if(MyUtil.isEmpty(ret)){
                myLogout(request);
                throw new YamiShopBindException("无法获取微信用户信息，"+"请在公众号"+mall.getMpName() + "中点击菜单“"+mall.getMenuName()+"”进入商城");
            }
            json= JSON.parseObject(ret);
            nickname=json.getString("nickname");
            //nickname=new String(nickname.getBytes(StandardCharsets.ISO_8859_1),StandardCharsets.UTF_8);
            headimgurl=json.getString("headimgurl");
            Integer sex=json.getInteger("sex");
//callSaveWxUser
            Map<String,Object> map=new HashMap<>();
            map.put("popenid",openid);
            map.put("pnickname",nickname);
            map.put("pheadimgurl",headimgurl);
            map.put("psex",sex);
            map.put("pmallid",mallid);
            //map.put("phost",wxLoginParam.getHost());
            userService.callSaveWxUser(map);
            logger.info("---------------------callSaveWxUser-------------------");
            logger.info(map.toString());
            if((Integer)map.get("pret")==0){
                logger.info("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! "+(String)map.get("pmsg"));
                myLogout(request);
                throw new YamiShopBindException((String)map.get("pmsg"));
            }
            userid=(String) map.get("puserid");
            phone=(String)map.get("pphone");
            logger.info("userid="+userid);



/*
            //获取图片
            QueryWrapper<TMediaUser> wrapper = new QueryWrapper<>();
            wrapper.eq("openid" , openid);
            List<TMediaUser> tMediaUserList = tMediaUserMapper.selectList(wrapper);
            request.setAttribute("list",tMediaUserList);

 */

        }else{
            myLogout(request);
            throw new YamiShopBindException("无法获取微信用户信息，"+"请在公众号"+mall.getMpName() + "中点击菜单“"+mall.getMenuName()+"”进入商城");


        }
        // 2. 登录
        UserInfoInTokenBO userInfoInTokenBO = new UserInfoInTokenBO();
        userInfoInTokenBO.setUserId(userid);
        userInfoInTokenBO.setNickName(nickname);
        userInfoInTokenBO.setPic(headimgurl);
        userInfoInTokenBO.setWxOpenId(openid);  //微信openid
        userInfoInTokenBO.setSysType(SysTypeEnum.ORDINARY.value());
        userInfoInTokenBO.setIsAdmin(0);
        userInfoInTokenBO.setEnabled(true);
        userInfoInTokenBO.setWxAppId(mall.getAppid());
        userInfoInTokenBO.setMallId(mallid);
        userInfoInTokenBO.setMallName(mall.getMallName());
        userInfoInTokenBO.setMchId(mp.getMchid());
        userInfoInTokenBO.setPhone(phone);





        logger.info("==================== set userInfoInTokenBO=============");
        logger.info(userInfoInTokenBO.toString());
        // 存储token返回vo
        TokenInfoVO tokenInfoVO = tokenStore.storeAndGetVo(userInfoInTokenBO);
        tokenInfoVO.setNickName(nickname);
        tokenInfoVO.setPic(headimgurl);
        tokenInfoVO.setMallType(mall.getMallType());
        tokenInfoVO.setCustomerServ(mall.getCustomerServ());

        ServerResponseEntity sre= ServerResponseEntity.success(tokenInfoVO);


        logger.info("=================微信公众号登录===============");
        logger.info(sre.toString());
        return sre;
    }

    @PutMapping("/updatePwd")
    @Operation(summary = "修改密码" , description = "修改密码")
    public ServerResponseEntity<Void> updatePwd(@Valid @RequestBody UserRegisterParam userPwdUpdateParam) {
        User user = userService.getOne(new LambdaQueryWrapper<User>().eq(User::getNickName, userPwdUpdateParam.getNickName()));
        if (user == null) {
            // 无法获取用户信息
            throw new YamiShopBindException("无法获取用户信息");
        }
        String decryptPassword = passwordManager.decryptPassword(userPwdUpdateParam.getPassWord());
        if (StrUtil.isBlank(decryptPassword)) {
            // 新密码不能为空
            throw new YamiShopBindException("新密码不能为空");
        }
        String password = passwordEncoder.encode(decryptPassword);
        if (StrUtil.equals(password, user.getLoginPassword())) {
            // 新密码不能与原密码相同
            throw new YamiShopBindException("新密码不能与原密码相同");
        }
        user.setModifyTime(new Date());
        user.setLoginPassword(password);
        userService.updateById(user);
        return ServerResponseEntity.success();
    }

    @PostMapping("/login")
    @Operation(summary = "账号密码(用于前端登录)" , description = "通过账号/手机号/用户名密码登录，还要携带用户的类型，也就是用户所在的系统")
    public ServerResponseEntity<TokenInfoVO> login(
            @Valid @RequestBody AuthenticationDTO authenticationDTO) {
        String mobileOrUserName = authenticationDTO.getUserName();
        User user = getUser(mobileOrUserName);

        String decryptPassword = passwordManager.decryptPassword(authenticationDTO.getPassWord());

        // 半小时内密码输入错误十次，已限制登录30分钟
        passwordCheckManager.checkPassword(SysTypeEnum.ORDINARY,authenticationDTO.getUserName(), decryptPassword, user.getLoginPassword());

        UserInfoInTokenBO userInfoInToken = new UserInfoInTokenBO();
        userInfoInToken.setUserId(user.getUserId());
        userInfoInToken.setSysType(SysTypeEnum.ORDINARY.value());
        userInfoInToken.setEnabled(user.getStatus() == 1);
        userInfoInToken.setWxOpenId(user.getWxid());   //测试使用，可以删除
        userInfoInToken.setMallId(2);  //测试使用，可以删除

        logger.info(userInfoInToken.toString());
        // 存储token返回vo
        TokenInfoVO tokenInfoVO = tokenStore.storeAndGetVo(userInfoInToken);
        tokenInfoVO.setNickName(user.getNickName());
        tokenInfoVO.setPic(user.getPic());
        return ServerResponseEntity.success(tokenInfoVO);
    }

    private User getUser(String mobileOrUserName) {
        User user = null;
        // 手机验证码登陆，或传过来的账号很像手机号
        if (PrincipalUtil.isMobile(mobileOrUserName)) {
            user = userMapper.selectOne(new LambdaQueryWrapper<User>().eq(User::getUserMobile, mobileOrUserName).eq(User::getMallid,0));
        }
        // 如果不是手机验证码登陆， 找不到手机号就找用户名
        if  (user == null) {
            user = userMapper.selectOneByUserName(mobileOrUserName);
        }
        if (user == null) {
            throw new YamiShopBindException("账号或密码不正确");
        }
        return user;
    }
}
